package com.shuwen.gcdj.service;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.shuwen.gcdj.common.exception.ApiException;
import com.shuwen.gcdj.common.util.BeanUtil;
import com.shuwen.gcdj.common.util.FrpStringUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Nonnull;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;

import static com.shuwen.gcdj.common.constant.Constants.*;
import static java.util.stream.Collectors.toSet;

/**
 * 服务基础类
 *
 * @param <T>
 */
public class BaseService<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> {

    private static final String NOT_EXIST_SUFFIX = ".not.exist";
//将年-月-日转换成 月-日
    private static final String DATATIMEMOTCH = "MM-dd";

    //将年-月-日转换成 月-日
    private static final String DATATIMEYEAR = "yyy-MM-dd";

    protected Logger log = LoggerFactory.getLogger(this.getClass());

    /**
     * 转时间格式为 月-日 的字符串
     * @param dataList
     * @return
     */
    public static String getDateList(List<String> dataList){
        SimpleDateFormat dtf = new SimpleDateFormat(DATATIMEMOTCH);
        SimpleDateFormat year = new SimpleDateFormat(DATATIMEYEAR);
        String str = "";
        int i = 0;
        try{
            for (String s : dataList){
                Date parse = year.parse(s);
                i++;
                if(i == 1){
                    str = str + dtf.format(parse);
                }else{
                    str = str + "," + dtf.format(parse);
                }
            }
        }catch (Exception e){
            throw new ApiException("时间转换失败");
        }
        return str;
    }

    /**
     * ,号隔开
     * @param dataList
     * @return
     */
    public static String getDateListToString(List<String> dataList){
        String str = "";
        int i = 0;
        for (String s : dataList){
            i++;
            if(i == 1){
                str = str + s;
            }else{
                str = str + "," + s;
            }
        }
        return str;
    }

    /**
     * 按天算时间段总数
     * @param starDate 开始时间
     * @param endDate  结束时间
     * @return
     */
    public static List<String> getDateList(String starDate ,String endDate){
        if(StringUtils.isEmpty(starDate) || StringUtils.isEmpty(endDate)){
            throw new ApiException("参数不能为空");
        }
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
        List<String> dateList = new ArrayList<>();
        try{
            Calendar calendar = new GregorianCalendar();
            Date starD = simpleDateFormat.parse(starDate);
            calendar.setTime(starD);
            Long endTime = simpleDateFormat.parse(endDate).getTime();
            Long starTime = starD.getTime();
            while (starTime <= endTime){
                dateList.add(sf.format(new Date(starTime)));
                calendar.add(calendar.DATE,1);
                starTime = calendar.getTime().getTime();
            }
        }catch (Exception e){
            throw new ApiException("时间格式转换失败");
        }
        return dateList;
    }

    public String getDateStr(String date){
        String[] split = date.split("-");
        String s = "";
        for(int i = 1 ; i < split.length;i++){
            if(i == 1){
                s = s + split[i] + "-";
                continue;
            }
            s = s + split[i];
        }
        return s.replace(" 00:00:00","");
    }

    /**
     * 批量保存数量
     */
    @Value("${save.batch.number:300}")
    private int saveBatchNumber;

    /**
     * 获取泛型对相应的Class对象
     *
     * @return <p>@author 刘朋</p>
     * <br/>date 2018-11-12
     */
    private Class<T> getTClass() {
        ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
        return (Class) type.getActualTypeArguments()[1];
    }

    /**
     * 批量设置单属性
     *
     * @param list            list
     * @param targetIdName    targetIdName
     * @param sourceFieldName sourceFieldName
     * @param targetFieldName targetFieldName
     * @param <T1>
     */
    public <T1> void setInfoBatch(List<T1> list, String targetIdName, String sourceFieldName, String targetFieldName) {
        setInfoBatch(list, targetIdName, BeanUtil.createMap(sourceFieldName, targetFieldName));
    }

    /**
     * 批量设置多属性
     *
     * @param list         list
     * @param targetIdName targetIdName
     * @param fieldMap     fieldMap
     * @param <T1>
     */
    public <T1> void setInfoBatch(List<T1> list, String targetIdName, Map<String, String> fieldMap) {
        if (CollectionUtil.isEmpty(list) || CollectionUtil.isEmpty(fieldMap) || StringUtils.isBlank(targetIdName)) {
            return;
        }
        Set<String> targetIds = BeanUtil.getStringFields(list, targetIdName);
        if (CollectionUtil.isEmpty(targetIds)) {
            return;
        }
        List<T> beanList = baseMapper.selectBatchIds(targetIds);
        if (CollectionUtil.isEmpty(beanList)) {
            return;
        }
        list.forEach(bean -> {
            Object idObject = BeanUtil.getFieldValue(bean, targetIdName);
            if (idObject == null) {
                return;
            }
            String id = idObject.toString();
            T sourceBean = beanList.stream().filter(e -> {
                Object sourceId = BeanUtil.getFieldValue(e, ID);
                return sourceId != null && sourceId.toString().equals(id);
            }).findFirst().orElse(null);
            if (sourceBean == null) {
                return;
            }
            fieldMap.entrySet().iterator().forEachRemaining(item -> {
                Object value = BeanUtil.getFieldValue(sourceBean, item.getKey());
                BeanUtil.setFieldValue(bean, item.getValue(), value);
            });
        });
    }

    public <T1> void setInfoBatch(List<T1> list, Function<T1, String> idFun, BiConsumer<T1, T> fieldMap,
                                  boolean joinId) {
        if (CollectionUtil.isEmpty(list)) {
            return;
        }
        Set<String> targetIds;
        if (joinId) {
            targetIds = list.stream().filter(t -> StringUtils.isNotBlank(idFun.apply(t)))
                    .flatMap(t -> Arrays.stream(idFun.apply(t).split(COMMA))).collect(toSet());
        } else {
            targetIds = list.stream().filter(t -> StringUtils.isNotBlank(idFun.apply(t))).map(idFun).collect(toSet());
        }
        if (CollectionUtil.isEmpty(targetIds)) {
            return;
        }
        List<T> beanList = baseMapper.selectBatchIds(targetIds);
        if (CollectionUtil.isEmpty(beanList)) {
            return;
        }
        list.forEach(bean -> setInfo(bean, idFun, beanList, fieldMap, joinId));
    }

    /**
     * 设置信息
     *
     * @param bean bean
     * @param <T1> 泛型
     */
    private <T1> void setInfo(T1 bean, Function<T1, String> idFun, List<T> beanList, BiConsumer<T1, T> fieldMap,
                              boolean joinId) {
        String id = idFun.apply(bean);
        if (StringUtils.isBlank(id)) {
            return;
        }
        beanList.stream().filter(e -> {
            Object sourceId = BeanUtil.getFieldValue(e, ID);
            if (sourceId != null) {
                String sId = sourceId.toString().trim();
                if (joinId) {
                    return id.equals(sId) || id.startsWith(sId + COMMA) || id.endsWith(COMMA + sId) || id
                            .contains(COMMA + sId + COMMA);
                } else {
                    return id.equals(sourceId.toString());
                }
            }
            return false;
        }).forEach(sourceBean -> fieldMap.accept(bean, sourceBean));
    }

    public <T1> void setInfoBatch(List<T1> list, Function<T1, String> idFun, BiConsumer<T1, T> fieldMap) {
        setInfoBatch(list, idFun, fieldMap, false);
    }

    /**
     * 校验是否存在
     *
     * @param id id
     */
    public void checkExist(String id) {
        String className = FrpStringUtil.toLowerCaseFirstOne(getTClass().getSimpleName());
        if (StringUtils.isBlank(id)) {
            throw new ApiException(className + NOT_EXIST_SUFFIX);
        }
        // 根据ID查询是否存在该实体
        int count = count(new QueryWrapper<T>().eq(ID, id));
        if (count == 0) {
            throw new ApiException(className + NOT_EXIST_SUFFIX);
        }
    }

    /**
     * 校验是否存在,并抛异常
     *
     * @param wrapper wrapper
     */
    public void checkExist(@Nonnull Wrapper<T> wrapper) {
        String className = FrpStringUtil.toLowerCaseFirstOne(getTClass().getSimpleName());
        // 根据查询器是否存在该实体
        int count = count(wrapper);
        if (count == 0) {
            throw new ApiException(className + NOT_EXIST_SUFFIX);
        }
    }

    public boolean checkIfExist(String id) {
        if (StringUtils.isBlank(id)) {
            return false;
        }
        // 根据ID查询是否存在该实体
        int count = count(new QueryWrapper<T>().eq(ID, id));
        return count != 0;
    }

    public boolean checkIfExist(Wrapper<T> wrapper) {
        // 根据查询器是否存在该实体
        int count = count(wrapper);
        return count != 0;
    }

    /**
     * 校验是否存在并返回
     *
     * @param id id
     */
    public T checkExistReturn(String id) {
        String className = FrpStringUtil.toLowerCaseFirstOne(getTClass().getSimpleName());
        if (StringUtils.isBlank(id)) {
            throw new ApiException(className + NOT_EXIST_SUFFIX);
        }
        // 根据ID查询是否存在该对象
        T bean = getById(id);
        if (bean == null) {
            throw new ApiException(className + NOT_EXIST_SUFFIX);
        }
        return bean;
    }

    public T checkExistReturn(@Nonnull Wrapper<T> wrapper) {
        String className = FrpStringUtil.toLowerCaseFirstOne(getTClass().getSimpleName());
        // 根据查询器是否存在该实体
        T bean = getOne(wrapper);
        if (bean == null) {
            throw new ApiException(className + NOT_EXIST_SUFFIX);
        }
        return bean;
    }


    /**
     * 批量新增实体类
     *
     * @param list list
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveBatch(Collection<T> list) {
        if (CollectionUtil.isEmpty(list)) {
            return false;
        }
        list.forEach(this::save);
        return true;
    }

    /**
     * 批量新增实体类 线程池
     *
     * @param list        list
     * @param batchNumber 每次批量保存条数
     */
    /*public boolean saveBatchUseThreadPool(List<T> list, int batchNumber) {
        if (CollectionUtil.isEmpty(list)) {
            return false;
        }
        if (this.baseMapper instanceof FrpBaseMapper) {
            FrpBaseMapper crmBaseMapper = (FrpBaseMapper) baseMapper;
            List<List<T>> partitions = Lists.partition(list, batchNumber);
            partitions.forEach(crmBaseMapper::batchSave);
            return true;
        }
        return false;
    }*/

    /**
     * 批量新增实体类 线程池
     *
     * @param list list
     */
    /*public boolean saveBatchUseThreadPool(List<T> list) {
        return saveBatchUseThreadPool(list, saveBatchNumber);
    }*/

    /**
     * 批量更新实体类
     *
     * @param list list
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateBatchById(Collection<T> list) {
        if (CollectionUtil.isEmpty(list)) {
            return false;
        }
        list.forEach(this::updateById);
        return true;
    }

    /**
     * 批量新增或更新实体类
     *
     * @param list list
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrUpdateBatch(Collection<T> list) {
        if (CollectionUtil.isEmpty(list)) {
            return false;
        }
        list.forEach(this::saveOrUpdate);
        return true;
    }

    /**
     * 批量删除实体列表
     *
     * @param idList 主键ID列表
     */
    @Override
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        if (CollectionUtil.isEmpty(idList)) {
            return true;
        }
        return SqlHelper.retBool(getBaseMapper().deleteBatchIds(idList));
    }

    /**
     * 查询（根据ID 批量查询）
     *
     * @param idList 主键ID列表
     */
    @Override
    public List<T> listByIds(Collection<? extends Serializable> idList) {
        if (CollectionUtil.isEmpty(idList)) {
            return Collections.emptyList();
        }
        return this.getBaseMapper().selectBatchIds(idList);
    }

    /**
     * 获取查询器
     */
    public LambdaQueryWrapper<T> lambdaQueryWapper() {
        return new LambdaQueryWrapper<>();
    }

    /**
     * 获取查询器
     *
     * @param clazz clazz
     * @param <T1>
     */
    public <T1> LambdaQueryWrapper<T1> lambdaQueryWapper(Class<T1> clazz) {
        return new LambdaQueryWrapper<>();
    }

    /**
     * 获取更新器
     *
     * @return 返回当前类更新器
     */
    public LambdaUpdateWrapper<T> lambdaUpdateWapper() {
        return new LambdaUpdateWrapper<>();
    }

    /**
     * 根据ID获取名称
     *
     * @param id id
     */
    public String getNameById(String id) {
        return getFieldById(id, NAME, String.class);
    }

    /**
     * 根据ID获取指定字段
     *
     * @param id         id
     * @param fieldName  字段名
     * @param fieldClass 字段类型
     * @return 返回指定字段值
     */
    public <T1> T1 getFieldById(String id, String fieldName, Class<T1> fieldClass) {
        if (StringUtils.isBlank(id) || StringUtils.isBlank(fieldName) || fieldClass == null) {
            return null;
        }
        T bean = getById(id);
        if (bean == null) {
            return null;
        }
        Object value = BeanUtil.getFieldValue(bean, fieldName);
        return value == null ? null : fieldClass.cast(value);
    }

    /**
     * 根据名称获取ID
     *
     * @param name name
     */
    public String getIdByName(String name) {
        if (StringUtils.isBlank(name)) {
            return null;
        }
        List<T> list = list(new QueryWrapper<T>().eq(NAME, name));
        if (CollectionUtil.isEmpty(list)) {
            return null;
        }
        Object value = BeanUtil.getFieldValue(list.get(0), ID);
        return value == null ? null : value.toString();
    }

    /**
     * 获取导入map
     */
    public Map<String, String> getImportMap() {
        List<T> list = list();
        Map<String, String> map = new HashMap<>();
        list.stream()
                .filter(item -> BeanUtil.getFieldValue(item, NAME) != null && BeanUtil.getFieldValue(item, ID) != null)
                .forEach(item -> map
                        .put((String) BeanUtil.getFieldValue(item, NAME), (String) BeanUtil.getFieldValue(item, ID)));
        return map;
    }

}
